<template>
    <div ref="outerWrapper" :class="wrapperClasses">
        <div v-if="isHorizontal" :class="`${prefix}-horizontal`">
            <div :style="{right: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'left-pane']"><slot name="left" /></div>
            <div :class="`${prefix}-trigger-con`" :style="{left: `${offset}%`}" @mousedown="handleMousedown">
                <slot name="trigger">
                    <trigger mode="vertical" />
                </slot>
            </div>
            <div :style="{left: `${offset}%`}" :class="[`${prefix}-pane`, 'right-pane']"><slot name="right" /></div>
        </div>
        <div v-else :class="`${prefix}-vertical`">
            <div :style="{bottom: `${anotherOffset}%`}" :class="[`${prefix}-pane`, 'top-pane']"><slot name="top" /></div>
            <div :class="`${prefix}-trigger-con`" :style="{top: `${offset}%`}" @mousedown="handleMousedown">
                <slot name="trigger">
                    <trigger mode="horizontal" />
                </slot>
            </div>
            <div :style="{top: `${offset}%`}" :class="[`${prefix}-pane`, 'bottom-pane']"><slot name="bottom" /></div>
        </div>
    </div>
</template>

<script>
import {oneOf, on, off} from '@/libs/tools'
import Trigger from './trigger.vue'
export default {
    name: 'SplitPane',
    components: {
        Trigger
    },
    props: {
        value: {
            type: [Number, String],
            default: 0.5
        },
        mode: {
            validator(value) {
                return oneOf(value, ['horizontal', 'vertical'])
            },
            default: 'horizontal'
        },
        min: {
            type: [Number, String],
            default: '40px'
        },
        max: {
            type: [Number, String],
            default: '40px'
        }
    },
    /**
     * Events
     * @on-move-start
     * @on-moving 返回值：事件对象，但是在事件对象中加入了两个参数：atMin(当前是否在最小值处), atMax(当前是否在最大值处)
     * @on-move-end
     */
    data() {
        return {
            prefix: 'ivu-split',
            offset: 0,
            oldOffset: 0,
            isMoving: false
        }
    },
    computed: {
        wrapperClasses() {
            return [`${this.prefix}-wrapper`, this.isMoving ? 'no-select' : '']
        },
        isHorizontal() {
            return this.mode === 'horizontal'
        },
        anotherOffset() {
            return 100 - this.offset
        },
        valueIsPx() {
            return typeof this.value === 'string'
        },
        offsetSize() {
            return this.isHorizontal ? 'offsetWidth' : 'offsetHeight'
        },
        computedMin() {
            return this.getComputedThresholdValue('min')
        },
        computedMax() {
            return this.getComputedThresholdValue('max')
        }
    },
    methods: {
        px2percent(numerator, denominator) {
            return parseFloat(numerator) / parseFloat(denominator)
        },
        getComputedThresholdValue(type) {
            let size = this.$refs.outerWrapper[this.offsetSize]
            if (this.valueIsPx) return typeof this[type] === 'string' ? this[type] : size * this[type]
            else return typeof this[type] === 'string' ? this.px2percent(this[type], size) : this[type]
        },
        getMin(value1, value2) {
            if (this.valueIsPx) return `${Math.min(parseFloat(value1), parseFloat(value2))}px`
            else return Math.min(value1, value2)
        },
        getMax(value1, value2) {
            if (this.valueIsPx) return `${Math.max(parseFloat(value1), parseFloat(value2))}px`
            else return Math.max(value1, value2)
        },
        getAnotherOffset(value) {
            let res = 0
            if (this.valueIsPx) res = `${this.$refs.outerWrapper[this.offsetSize] - parseFloat(value)}px`
            else res = 1 - value
            return res
        },
        handleMove(e) {
            let pageOffset = this.isHorizontal ? e.pageX : e.pageY
            let offset = pageOffset - this.initOffset
            let outerWidth = this.$refs.outerWrapper[this.offsetSize]
            let value = this.valueIsPx
                ? `${parseFloat(this.oldOffset) + offset}px`
                : this.px2percent(outerWidth * this.oldOffset + offset, outerWidth)
            let anotherValue = this.getAnotherOffset(value)
            if (parseFloat(value) <= parseFloat(this.computedMin)) value = this.getMax(value, this.computedMin)
            if (parseFloat(anotherValue) <= parseFloat(this.computedMax))
                value = this.getAnotherOffset(this.getMax(anotherValue, this.computedMax))
            e.atMin = this.value === this.computedMin
            e.atMax = this.valueIsPx
                ? this.getAnotherOffset(this.value) === this.computedMax
                : this.getAnotherOffset(this.value).toFixed(5) === this.computedMax.toFixed(5)
            this.$emit('input', value)
            this.$emit('on-moving', e)
        },
        handleUp() {
            this.isMoving = false
            off(document, 'mousemove', this.handleMove)
            off(document, 'mouseup', this.handleUp)
            this.$emit('on-move-end')
        },
        handleMousedown(e) {
            this.initOffset = this.isHorizontal ? e.pageX : e.pageY
            this.oldOffset = this.value
            this.isMoving = true
            on(document, 'mousemove', this.handleMove)
            on(document, 'mouseup', this.handleUp)
            this.$emit('on-move-start')
        }
    },
    watch: {
        value() {
            this.offset =
                ((this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000) / 100
        }
    },
    mounted() {
        this.$nextTick(() => {
            this.offset =
                ((this.valueIsPx ? this.px2percent(this.value, this.$refs.outerWrapper[this.offsetSize]) : this.value) * 10000) / 100
        })
    }
}
</script>

<style lang="less">
@import './index.less';
</style>
